﻿// ----------------------------------------------------------------------------
// assert.h
// ----------------------------------------------------------------------------
#pragma once
#include <fw/base/core/macros.h>
#include <fw/base/core/debugconsole.h>
#include <assert.h>
#include <cstdarg>

namespace fw
{
#if USING(FW_DEBUG)
    FW_FORCE_INLINE void AssertionFailure(const char *exp, const char *file, size_t line, const char *function)
    {
        FW_PRINTF("%s(%d):%s() FW_ASSERT(%s)\n", file, line, function, exp);
        FW_PLATFORM_DEBUG_BREAK();
    }
    
    FW_FORCE_INLINE void AssertionFailure(const char *exp, const char *file, size_t line, const char *function, const char *pszfmt, ...)
    {
        FW_PRINTF("%s(%d):%s() FW_ASSERT(%s, \"", file, line, function, exp);
        
        va_list list;
        va_start(list, pszfmt);
        FW_VPRINTF(pszfmt, list);	
        va_end(list);
        
        FW_PRINTF("\")\n");
        FW_PLATFORM_DEBUG_BREAK();
    }
    
    FW_FORCE_INLINE void AssertionFailure(const char *exp, const char *file, size_t line, const char *function, const wchar_t *pszfmt, ...)
    {
        FW_PRINTF("%s(%d):%s() FW_ASSERT(%s, \"", file, line, function, exp);
        
        va_list list;
        va_start(list, pszfmt);
        FW_VWPRINTF(pszfmt, list);	
        va_end(list);
        
        FW_PRINTF("\")\n");
        FW_PLATFORM_DEBUG_BREAK();
    }
    
    FW_FORCE_INLINE void DebugBreak(const char *file, size_t line, const char *function)
    {
        FW_PRINTF("%s(%d):%s() FW_BREAK()\n", file, line, function);
        FW_PLATFORM_DEBUG_BREAK();
    }
    
    FW_FORCE_INLINE void DebugBreak(const char *file, size_t line, const char *function, const char *pszfmt, ...)
    {
        FW_PRINTF("%s(%d):%s() FW_BREAK(\"", file, line, function);
        
        va_list list;
        va_start(list, pszfmt);
        FW_VPRINTF(pszfmt, list);	
        va_end(list);
        
        FW_PRINTF("\")\n");
        FW_PLATFORM_DEBUG_BREAK();
    }
    
    FW_FORCE_INLINE void DebugBreak(const char *file, size_t line, const char *function, const wchar_t *pszfmt, ...)
    {
        FW_PRINTF("%s(%d):%s() FW_BREAK(\"", file, line, function);
        
        va_list list;
        va_start(list, pszfmt);
        FW_VWPRINTF(pszfmt, list);	
        va_end(list);
        
        FW_PRINTF("\")\n");
        FW_PLATFORM_DEBUG_BREAK();
    }
#endif // FW_DEBUG
} // namespace fw

// アサーションマクロはDEBUG時のみ存在する
#if USING(FW_DEBUG)
// DEBUG
#if USING(FW_COMPILER_MSVC)
// MSVC
#define FW_ASSERT(CONDITION, ...) ((CONDITION) ? true : ::fw::AssertionFailure(#CONDITION, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__))
#define FW_BREAK(...) ::fw::DebugBreak(__FILE__, __LINE__, FW_FUNCTION, __VA_ARGS__)
#else
// OTHER
#define FW_ASSERT(CONDITION, ...) if (!(CONDITION)) ::fw::AssertionFailure(#CONDITION, __FILE__, __LINE__, FW_FUNCTION, ##__VA_ARGS__)
#define FW_BREAK(...) ::fw::DebugBreak(__FILE__, __LINE__, FW_FUNCTION, ##__VA_ARGS__)
#endif
#else
// NDEBUG
#define FW_ASSERT(...)
#define FW_BREAK(...)
#endif

// デバッグ時のみ評価する.
#if USING(FW_DEBUG)
#define FW_IF_BUILD_ASSERTION(...)				__VA_ARGS__
#define FW_IF_NOT_BUILD_ASSERTION(...)			__noop
#else
#define FW_IF_BUILD_ASSERTION(...)
#define FW_IF_NOT_BUILD_ASSERTION(...)			__VA_ARGS__
#endif

#define FW_VALIDATE(cond)				{ \
											bool bCond = ( cond ); FW_UNUSED(bCond); \
											FW_ASSERT( bCond ); \
										}
